import { Node } from '../core/node.js';
import { mat4, vec3 } from '../gl-matrix/index.js';;

export class Camera extends Node {
    constructor() {
        super();

        this._projectionMatrix = mat4.create();
        this._projectionMatrixInverse = mat4.create();
        this._worldMatrixInverse = mat4.create();
    }

    get projectionMatrix() {
        return this._projectionMatrix;
    }

    get projectionMatrixInverse() {
        return this._projectionMatrixInverse;
    }

    get worldMatrixInverse() {
        if (!this._worldMatrix) {
            this._dirtyWorldMatrix = true;
            this._worldMatrix = mat4.create();
        }

        if (this._dirtyWorldMatrix || this._dirtyTRS) {
            if (this.parent) {
                mat4.mul(this._worldMatrix, this.parent.worldMatrix, this._updateLocalMatrix());
            } else {
                mat4.copy(this._worldMatrix, this._updateLocalMatrix());
            }

            mat4.invert(this._worldMatrixInverse, this._worldMatrix);

            this._dirtyWorldMatrix = false;
        }

        return this._worldMatrixInverse;
    }

    get worldMatrix() {
        if (!this._worldMatrix) {
            this._dirtyWorldMatrix = true;
            this._worldMatrix = mat4.create();
        }

        if (this._dirtyWorldMatrix || this._dirtyTRS) {
            if (this.parent) {
                mat4.mul(this._worldMatrix, this.parent.worldMatrix, this._updateLocalMatrix());
            } else {
                mat4.copy(this._worldMatrix, this._updateLocalMatrix());
            }

            mat4.invert(this._worldMatrixInverse, this._worldMatrix);

            this._dirtyWorldMatrix = false;
        }

        return this._worldMatrix;
    }

    unproject(out, a, width, height) {
        a[0] = (a[0] / width) * 2 - 1;
        a[1] = -(a[1] / height) * 2 + 1;

        vec3.transformMat4(out, a, this.projectionMatrixInverse);
        vec3.transformMat4(out, out, this.worldMatrix);
    }

    project(out, a, width, height) {
        vec3.transformMat4(out, a, this.worldMatrixInverse);
        vec3.transformMat4(out, out, this.projectionMatrix);

        out[0] = (out[0] + 1) * 0.5 * width;
        out[1] = (out[1] - 1) * -0.5 * height;
    }
}